﻿#region Using

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Vk.Methods.Photos;

#endregion

namespace Vk.Methods.Pages
{
    /// <summary>
    ///     Страницы
    /// </summary>
    public class Pages
    {
        private readonly Api _api;

        public Pages(Api api)
        {
            _api = api;
        }

        /// <summary>
        ///     Позволяет очистить кеш отдельных внешних страниц, которые могут быть прикреплены к записям ВКонтакте. После очистки
        ///     кеша при последующем прикреплении ссылки к записи, данные о странице будут обновлены.
        /// </summary>
        /// <param name="url">Адрес страницы, закешированную версию которой необходимо очистить </param>
        public async Task<bool> ClearCache(string url)
        {
            if (string.IsNullOrWhiteSpace(url))
                throw new ArgumentException("url");

            var query = new ApiQuery("pages.clearCache", true)
                .Add("url", url);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Возвращает информацию о вики-странице.
        /// </summary>
        /// <param name="pageId">Идентификатор вики-страницы</param>
        /// <param name="title">Название страницы</param>
        /// <param name="ownerId">Идентификатор владельца вики-страницы</param>
        /// <param name="sitePreview">true — получаемая wiki страница является предпросмотром для прикрепленной ссылки. </param>
        /// <param name="global">true — требуется получить информацию о глобальной вики-странице.</param>
        /// <param name="needHtml">true — требуется вернуть html-представление страницы.</param>
        /// <param name="needSource">true — требуется вернуть содержимое страницы в вики-формате. </param>
        public async Task<Page> Get(int ownerId,
                                    int pageId,
                                    string title = null,
                                    bool? sitePreview = null,
                                    bool? global = null,
                                    bool? needHtml = null,
                                    bool? needSource = null)
        {
            var query = new ApiQuery("pages.get")
                .Add("owner_id", ownerId)
                .Add("page_id", pageId)
                .Add("title", title)
                .Add("site_preview", sitePreview)
                .Add("global", global)
                .Add("need_html", needHtml)
                .Add("need_source", needSource);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed ? new Page(result) : null;
        }

        /// <summary>
        ///     Возвращает список всех старых версий вики-страницы.
        /// </summary>
        /// <param name="pageId">Идентификатор вики-страницы </param>
        /// <param name="groupId">Идентификатор сообщества, которому принадлежит вики-страница </param>
        /// <param name="userId">Идентификатор пользователя, создавшего вики-страницу</param>
        /// <returns>Возвращает массив объектов page_version</returns>
        public async Task<List<HistoryPageObject>> GetHistory(int pageId, int? groupId = null, int? userId = null)
        {
            var query = new ApiQuery("pages.getHistory")
                .Add("page_id", pageId)
                .Add("group_id", groupId)
                .Add("user_id", userId);

            var result = await _api.Manager.Execute(query);

            if (_api.Manager.MethodSuccessed)
            {
                var nodes = result.SelectNodes("page_version");
                if (nodes != null && nodes.Any())
                    return nodes.Select(x => new HistoryPageObject(x)).ToList();
            }
            return null;
        }

        /// <summary>
        ///     Возвращает список вики-страниц в группе.
        /// </summary>
        /// <param name="groupId">
        ///     ID группы, где создана страница. Если параметр не указывать, возвращается список всех страниц,
        ///     созданных текущим пользователем.
        /// </param>
        /// <returns>Возвращает множество объектов page.</returns>
        public async Task<List<Page>> GetTitles(int groupId)
        {
            var query = new ApiQuery("pages.getTitles")
                .Add("group_id", groupId);

            var result = await _api.Manager.Execute(query);

            if (_api.Manager.MethodSuccessed)
            {
                var nodes = result.SelectNodes("page");
                if (nodes != null && nodes.Any())
                    return nodes.Select(x => new Page(x)).ToList();
            }
            return null;
        }

        /// <summary>
        ///     Возвращает текст одной из старых версий страницы.
        /// </summary>
        /// <param name="versionId">ID версии вики-страницы.</param>
        /// <param name="groupId">ID группы, где создана страница.</param>
        /// <param name="userId">Идентификатор пользователя, который создал страницу. </param>
        /// <param name="needHtml">Определяет, требуется ли в ответе html-представление версии вики-страницы.</param>
        public async Task<Page> GetVersion(int versionId,
                                                        int? groupId = null,
                                                        int? userId = null,
                                                        bool? needHtml = null)
        {
            var query = new ApiQuery("pages.getVersion")
                .Add("version_id", versionId)
                .Add("group_id", groupId)
                .Add("user_id", userId)
                .Add("need_html", needHtml);

            var result = await _api.Manager.Execute(query);

            if (_api.Manager.MethodSuccessed)
            {
                return new Page(result);
            }
            return null;
        }

        /// <summary>
        ///     Возвращает html-представление вики-разметки.
        /// </summary>
        /// <param name="text">Текст в вики-формате.</param>
        /// <param name="groupId">Идентификатор группы, в контексте которой интерпретируется данная страница.</param>
        /// <returns>В случае успеха возвращает экранированный html, соответствующий вики-разметке. </returns>
        public async Task<string> ParseWiki(string text, int? groupId = null)
        {
            if (string.IsNullOrWhiteSpace(text))
            {
                throw new ArgumentNullException(nameof(text));
            }

            var query = new ApiQuery("pages.parseWiki")
                .Add("text", text)
                .Add("group_id", groupId);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed ? result.String() : null;
        }

        /// <summary>
        ///     Сохраняет текст вики-страницы.
        /// </summary>
        /// <param name="pageId">
        ///     ID вики-страницы. Вместо pid может быть передан параметр title - название вики-страницы. В этом
        ///     случае если страницы с таким названием еще нет, она будет создана.
        /// </param>
        /// <param name="groupId">
        ///     ID группы, где создана страница. Вместо gid может быть передан параметр mid - id создателя
        ///     вики-страницы. В этом случае произойдет обращение не к странице группы, а к одной из личных вики-страниц
        ///     пользователя.
        /// </param>
        /// <param name="text">Новый текст страницы в вики-формате.</param>
        /// <param name="title">Название вики-страницы</param>
        /// <param name="userId">Идентификатор пользователя, создавшего вики-страницу</param>
        /// <returns>В случае успеха возвращает id созданной страницы. </returns>
        public async Task<int> Save(int pageId, int groupId, string text, int userId, string title)
        {
            if (text == null)
            {
                throw new ArgumentNullException(nameof(text));
            }

            var query = new ApiQuery("pages.save")
                .Add("page_id", pageId)
                .Add("group_id", groupId)
                .Add("text", text);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Int().HasValue ? result.Int().Value : -1;
        }

        /// <summary>
        ///     Сохраняет новые настройки доступа на чтение и редактирование вики-страницы.
        /// </summary>
        /// <param name="pageId">ID вики-страницы.</param>
        /// <param name="groupId">ID группы, где создана страница.</param>
        /// <param name="view">
        ///     Значение настройки доступа на чтение; описание значений Вы можете узнать странице, посвященной
        ///     методу pages.get.
        /// </param>
        /// <param name="edit">
        ///     Значение настройки доступа на редактирование; описание значений Вы можете узнать странице,
        ///     посвященной методу pages.get.
        /// </param>
        /// <param name="userId"> Идентификатор пользователя, создавшего вики-страницу</param>
        /// <returns>В случае успеха возвращает id страницы, доступ к которой был отредактирован. </returns>
        public async Task<int> SaveAccess(int pageId,
                                          int? groupId = null,
                                          int? userId = null,
                                          Privacy view = null,
                                          Privacy edit = null)
        {
            var query = new ApiQuery("pages.saveAccess")
                .Add("page_id", pageId)
                .Add("group_id", groupId)
                .Add("user_id", userId)
                .Add("view", view)
                .Add("edit", edit);

            var result = await _api.Manager.Execute(query);

            return _api.Manager.MethodSuccessed && result.Int().HasValue ? result.Int().Value : -1;
        }
    }
}